#ifndef YENTITY_FUNCTION_LINKER_IMP_H
#define YENTITY_FUNCTION_LINKER_IMP_H

	#define yCONNECT_CODE( argN,... ) \
		if ( signalMap.find( signalName ) == signalMap.end() ){		std::cout << "\n" << "Signal \"" << signalName << "\" does not exist";return;	}\
		\
		Functor * ofunc = new SpecificFunctor##argN##a __VA_ARGS__ ( destEntity , fp );\
		FunctorContainer *funcC = signalMap[ signalName ];\
		funcC->addFunction( ofunc );\
		\
		destEntity->functorLinks.push_back( funcC );
		
	#define yDISCONNECT_CODE( argN,... ) \
		if ( signalMap.find( signalName ) == signalMap.end() ){		\
			std::cout << "\n" << "Signal \"" << signalName << "\" does not exist, cannot be disconnected";return;	}\
		FunctorContainer *funcC = signalMap[ signalName ];\
		funcC->removeFunction( destEntity , fp );\
		\
		destEntity->removeFunctorLink( funcC );
		

	//Connections
	T1	void Entity::connect (const char *signalName , Entity *destEntity, void(Entity::*fp)(C)) {		yCONNECT_CODE(1,<C>);		}
	T2	void Entity::connect (const char *signalName , Entity *destEntity, void(Entity::*fp)(C,D)) {		yCONNECT_CODE(2,<C,D>);		}
	T3	void Entity::connect (const char *signalName , Entity *destEntity, void(Entity::*fp)(C,D,E)) {	yCONNECT_CODE(3,<C,D,E>);	}
	T4	void Entity::connect (const char *signalName , Entity *destEntity, void(Entity::*fp)(C,D,E,F)) {	yCONNECT_CODE(4,<C,D,E,F>);	}
	
	T1	void Entity::disconnect (const char *signalName , Entity *destEntity, void(Entity::*fp)(C)) {		yDISCONNECT_CODE(1,<C>);		}
	T2	void Entity::disconnect (const char *signalName , Entity *destEntity, void(Entity::*fp)(C,D)) {		yDISCONNECT_CODE(2,<C,D>);		}
	T3	void Entity::disconnect (const char *signalName , Entity *destEntity, void(Entity::*fp)(C,D,E)) {	yDISCONNECT_CODE(3,<C,D,E>);	}
	T4	void Entity::disconnect (const char *signalName , Entity *destEntity, void(Entity::*fp)(C,D,E,F)) {	yDISCONNECT_CODE(4,<C,D,E,F>);	}
	
	//Connections with default arguments supplied
	T1	void Entity::connect (const char *signalName , Entity* destinationEntity , void(Entity::*fp)(C), C c){
		connect(signalName,destinationEntity,fp);
		SpecificFunctor1a<C> * ofunc = ( SpecificFunctor1a<C> * ) signalMap[ signalName ]->functions.back();
		
		ofunc->defArg1 = c;
	}
	T2	void Entity::connect (const char *signalName , Entity* destinationEntity , void(Entity::*fp)(C,D), C c, D d){
		connect(signalName,destinationEntity,fp);
		SpecificFunctor2a<C,D> * ofunc = ( SpecificFunctor2a<C,D> * ) signalMap[ signalName ]->functions.back();
		
		ofunc->defArg1 = c;
		ofunc->defArg2 = d;
	}
	T3	void Entity::connect (const char *signalName , Entity* destinationEntity , void(Entity::*fp)(C,D,E), C c, D d, E e){
		connect(signalName,destinationEntity,fp);
		SpecificFunctor3a<C,D,E> * ofunc = ( SpecificFunctor3a<C,D,E> * ) signalMap[ signalName ]->functions.back();
		
		ofunc->defArg1 = c;
		ofunc->defArg2 = d;
		ofunc->defArg3 = e;
	}
	T4	void Entity::connect (const char *signalName , Entity* destinationEntity , void(Entity::*fp)(C,D,E,F), C c, D d, E e, F f){
		connect(signalName,destinationEntity,fp);
		SpecificFunctor4a<C,D,E,F> * ofunc = ( SpecificFunctor4a<C,D,E,F> * ) signalMap[ signalName ]->functions.back();
		
		ofunc->defArg1 = c;
		ofunc->defArg2 = d;
		ofunc->defArg3 = e;
		ofunc->defArg4 = f;		
	}
	
	#define yCALL_CODE( ... ) \
		typeof ( signalMap.begin() ) iter = signalMap.find( signalName );										\
		if ( iter == signalMap.end() ) {																		\
			std::cout << "\n" << "signal \"" << signalName << "\" called, but not such signal exists";return;	}		\
																												\
		iter->second->call( __VA_ARGS__ );
		
	//Call functions
	T1	void Entity::call ( const char *signalName, C c){						yCALL_CODE(c);			}
	T2	void Entity::call ( const char *signalName, C c, D d){					yCALL_CODE(c,d);		}
	T3	void Entity::call ( const char *signalName, C c, D d, E e){			yCALL_CODE(c,d,e);		}
	T4	void Entity::call ( const char *signalName, C c, D d, E e, F f){		yCALL_CODE(c,d,e,f);	}
	
	#undef T1
	#undef T2
	#undef T3
	#undef T4

#endif
